From: Phil Race Date: Mon, 23 Feb 2026 18:36:00 +0000 (+0000) Subject: [PATCH] 8337853: Remove SunLayoutEngineKey and SunLayoutEngineFactory and its cache... X-Git-Tag: archive/raspbian/25.0.5_7ea-1+rpi1~8 X-Git-Url: https://dgit.raspbian.org/%22http://www.example.com/cgi/%22/%22http:/www.example.com/cgi/%22?a=commitdiff_plain;h=14ce999f820ba4fcff69c338baa5d586618445c9;p=openjdk-25.git [PATCH] 8337853: Remove SunLayoutEngineKey and SunLayoutEngineFactory and its cache. Remove layout engine cache that causes temporary directory to fill up with the temporary font files. From 569d18fbe51a036629337c38230ae4892365a228 Mon Sep 17 00:00:00 2001 Bug-Ubuntu: https://bugs.launchpad.net/ubuntu/+source/openjdk-25/+bug/2155650 Bug: https://bugs.openjdk.org/browse/JDK-8337853 Origin: upstream, https://github.com/openjdk/jdk/commit/569d18fbe51a036629337c38230ae4892365a228 Reviewed-by: azvegint, dnguyen Gbp-Pq: Name jdk-8337853.diff --- diff --git a/src/java.desktop/share/classes/java/awt/Font.java b/src/java.desktop/share/classes/java/awt/Font.java index 2da68fd86..beed47c25 100644 --- a/src/java.desktop/share/classes/java/awt/Font.java +++ b/src/java.desktop/share/classes/java/awt/Font.java @@ -2709,7 +2709,7 @@ public class Font implements java.io.Serializable int limit, int flags) { - GlyphLayout gl = GlyphLayout.get(null); // !!! no custom layout engines + GlyphLayout gl = GlyphLayout.get(); StandardGlyphVector gv = gl.layout(this, frc, text, start, limit-start, flags, null); GlyphLayout.done(gl); diff --git a/src/java.desktop/share/classes/sun/font/ExtendedTextSourceLabel.java b/src/java.desktop/share/classes/sun/font/ExtendedTextSourceLabel.java index 784035f4f..d7cf30ad6 100644 --- a/src/java.desktop/share/classes/sun/font/ExtendedTextSourceLabel.java +++ b/src/java.desktop/share/classes/sun/font/ExtendedTextSourceLabel.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -329,7 +329,7 @@ class ExtendedTextSourceLabel extends ExtendedTextLabel implements Decoration.La int start = source.getStart(); int length = source.getLength(); - GlyphLayout gl = GlyphLayout.get(null); // !!! no custom layout engines + GlyphLayout gl = GlyphLayout.get(); gv = gl.layout(font, frc, context, start, length, flags, null); // ??? use textsource GlyphLayout.done(gl); diff --git a/src/java.desktop/share/classes/sun/font/GlyphLayout.java b/src/java.desktop/share/classes/sun/font/GlyphLayout.java index fe2a8bf25..df42cce34 100644 --- a/src/java.desktop/share/classes/sun/font/GlyphLayout.java +++ b/src/java.desktop/share/classes/sun/font/GlyphLayout.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -87,7 +87,6 @@ public final class GlyphLayout { // cached glyph layout data for reuse private static volatile GlyphLayout cache; // reusable - private LayoutEngineFactory _lef; // set when get is called, unset when done is called private TextRecord _textRecord; // the text we're working on, used by iterators private ScriptRun _scriptRuns; // iterator over script runs private FontRunIterator _fontRuns; // iterator over physical fonts in a composite @@ -100,91 +99,10 @@ public final class GlyphLayout { private int _typo_flags; private int _offset; - public static final class LayoutEngineKey { - private Font2D font; - private int script; - private int lang; - - LayoutEngineKey() { - } - - LayoutEngineKey(Font2D font, int script, int lang) { - init(font, script, lang); - } - - void init(Font2D font, int script, int lang) { - this.font = font; - this.script = script; - this.lang = lang; - } - - LayoutEngineKey copy() { - return new LayoutEngineKey(font, script, lang); - } - - Font2D font() { - return font; - } - - int script() { - return script; - } - - int lang() { - return lang; - } - - public boolean equals(Object rhs) { - if (this == rhs) return true; - if (rhs == null) return false; - try { - LayoutEngineKey that = (LayoutEngineKey)rhs; - return this.script == that.script && - this.lang == that.lang && - this.font.equals(that.font); - } - catch (ClassCastException e) { - return false; - } - } - - public int hashCode() { - return script ^ lang ^ font.hashCode(); - } - } - - public static interface LayoutEngineFactory { - /** - * Given a font, script, and language, determine a layout engine to use. - */ - public LayoutEngine getEngine(Font2D font, int script, int lang); - - /** - * Given a key, determine a layout engine to use. - */ - public LayoutEngine getEngine(LayoutEngineKey key); - } - - public static interface LayoutEngine { - /** - * Given a strike descriptor, text, rtl flag, and starting point, append information about - * glyphs, positions, and character indices to the glyphvector data, and advance the point. - * - * If the GVData does not have room for the glyphs, throws an IndexOutOfBoundsException and - * leave pt and the gvdata unchanged. - */ - public void layout(FontStrikeDesc sd, float[] mat, float ptSize, int gmask, - int baseIndex, TextRecord text, int typo_flags, Point2D.Float pt, GVData data); - } - /** - * Return a new instance of GlyphLayout, using the provided layout engine factory. - * If null, the system layout engine factory will be used. + * Return a possibly recycled instance of GlyphLayout */ - public static GlyphLayout get(LayoutEngineFactory lef) { - if (lef == null) { - lef = SunLayoutEngine.instance(); - } + public static GlyphLayout get() { GlyphLayout result = null; synchronized(GlyphLayout.class) { if (cache != null) { @@ -195,7 +113,6 @@ public final class GlyphLayout { if (result == null) { result = new GlyphLayout(); } - result._lef = lef; return result; } @@ -204,7 +121,6 @@ public final class GlyphLayout { * of GlyphLayout objects. */ public static void done(GlyphLayout gl) { - gl._lef = null; cache = gl; // object reference assignment is thread safe, it says here... } @@ -398,8 +314,6 @@ public final class GlyphLayout { } } - int lang = -1; // default for now - Font2D font2D = FontUtilities.getFont2D(font); if (font2D instanceof FontSubstitution) { font2D = ((FontSubstitution)font2D).getCompositeFont2D(); @@ -426,7 +340,7 @@ public final class GlyphLayout { } int gmask = _fontRuns.getGlyphMask(); int pos = _fontRuns.getPos(); - nextEngineRecord(start, pos, script, lang, pfont, gmask); + nextEngineRecord(start, pos, script, pfont, gmask); start = pos; } } @@ -435,7 +349,7 @@ public final class GlyphLayout { while (_scriptRuns.next()) { int limit = _scriptRuns.getScriptLimit(); int script = _scriptRuns.getScriptCode(); - nextEngineRecord(start, limit, script, lang, font2D, 0); + nextEngineRecord(start, limit, script, font2D, 0); start = limit; } } @@ -508,7 +422,7 @@ public final class GlyphLayout { this._gvdata.init(capacity); } - private void nextEngineRecord(int start, int limit, int script, int lang, Font2D font, int gmask) { + private void nextEngineRecord(int start, int limit, int script, Font2D font, int gmask) { EngineRecord er = null; if (_ercount == _erecords.size()) { er = new EngineRecord(); @@ -516,7 +430,7 @@ public final class GlyphLayout { } else { er = _erecords.get(_ercount); } - er.init(start, limit, font, script, lang, gmask); + er.init(start, limit, font, script, gmask); ++_ercount; } @@ -627,18 +541,18 @@ public final class GlyphLayout { private int limit; private int gmask; private int eflags; - private LayoutEngineKey key; - private LayoutEngine engine; + private Font2D font; + private int script; EngineRecord() { - key = new LayoutEngineKey(); } - void init(int start, int limit, Font2D font, int script, int lang, int gmask) { + void init(int start, int limit, Font2D font, int script, int gmask) { this.start = start; this.limit = limit; + this.font = font; + this.script = script; this.gmask = gmask; - this.key.init(font, script, lang); this.eflags = 0; // only request canonical substitution if we have combining marks @@ -659,14 +573,12 @@ public final class GlyphLayout { break; } } - - this.engine = _lef.getEngine(key); // flags? } void layout() { _textRecord.start = start; _textRecord.limit = limit; - engine.layout(_sd, _mat, ptSize, gmask, start - _offset, _textRecord, + SunLayoutEngine.layout(font, script, _sd, _mat, ptSize, gmask, start - _offset, _textRecord, _typo_flags | eflags, _pt, _gvdata); } } diff --git a/src/java.desktop/share/classes/sun/font/SunLayoutEngine.java b/src/java.desktop/share/classes/sun/font/SunLayoutEngine.java index f1d6de7d4..99d3987e5 100644 --- a/src/java.desktop/share/classes/sun/font/SunLayoutEngine.java +++ b/src/java.desktop/share/classes/sun/font/SunLayoutEngine.java @@ -1,4 +1,5 @@ /* + * Copyright (c) 2003, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -36,126 +37,22 @@ import sun.java2d.DisposerRecord; import java.awt.geom.Point2D; import java.lang.foreign.MemorySegment; -import java.lang.ref.SoftReference; import java.util.concurrent.ConcurrentHashMap; import java.util.WeakHashMap; -/* - * different ways to do this - * 1) each physical font2d keeps a hashtable mapping scripts to layout - * engines, we query and fill this cache. - * 2) we keep a mapping independent of font using the key Most likely - * few fonts will be used, so option 2 seems better - * - * Once we know which engine to use for a font, we always know, so we - * shouldn't have to recheck each time we do layout. So the cache is - * ok. - * - * Should we reuse engines? We could instantiate an engine for each - * font/script pair. The engine would hold onto the table(s) from the - * font that it needs. If we have multiple threads using the same - * engine, we still need to keep the state separate, so the native - * engines would still need to be allocated for each call, since they - * keep their state in themselves. If they used the passed-in GVData - * arrays directly (with some checks for space) then since each GVData - * is different per thread, we could reuse the layout engines. This - * still requires a separate layout engine per font, because of the - * table state in the engine. If we pushed that out too and passed it - * in with the native call as well, we'd be ok if the layout engines - * keep all their process state on the stack, but I don't know if this - * is true. Then we'd basically just be down to an engine index which - * we pass into native and then invoke the engine code (now a - * procedure call, not an object invocation) based on a switch on the - * index. There would be only half a dozen engine objects then, not - * potentially half a dozen per font. But we'd have to stack-allocate - * some state that included the pointer to the required font tables. - * - * Seems for now that the way to do things is to come in with a - * selector and the font. The selector indicates which engine to use, - * the engine is stack allocated and initialized with the required - * font tables (the selector indicates which). Then layout is called, - * the contents are copied (or not), and the stack is destroyed on - * exit. So the association is between the font/script (layout engine - * desc) and one of a few permanent engine objects, which are - * handed the key when they need to process something. In the native - * case, the engine holds an index, and just passes it together with - * the key info down to native. Some default cases are the 'default - * layout' case that just runs the c2gmapper, this stays in java and - * just uses the mapper from the font/strike. Another default case - * might be the unicode arabic shaper, since this doesn't care about - * the font (or script or lang?) it wouldn't need to extract this - * data. It could be (yikes) ported back to java even to avoid - * upcalls to check if the font supports a particular unicode - * character. - * - * I'd expect that the majority of scripts use the default mapper for - * a particular font. Loading the hashtable with 40 or so keys 30+ of - * which all map to the same object is unfortunate. It might be worth - * instead having a per-font list of 'scripts with non-default - * engines', e.g. the factory has a hashtable mapping fonts to 'script - * lists' (the factory has this since the design potentially has other - * factories, though I admit there's no client for this yet and no - * public api) and then the script list is queried for the script in - * question. it can be preloaded at creation time with all the - * scripts that don't have default engines-- either a list or a hash - * table, so a null return from the table means 'default' and not 'i - * don't know yet'. - * - * On the other hand, in most all cases the number of unique - * script/font combinations will be small, so a flat hashtable should - * suffice. - * */ -public final class SunLayoutEngine implements LayoutEngine, LayoutEngineFactory { +public final class SunLayoutEngine { + static { FontManagerNativeLibrary.load(); } - private LayoutEngineKey key; - - private static LayoutEngineFactory instance; - - public static LayoutEngineFactory instance() { - if (instance == null) { - instance = new SunLayoutEngine(); - } - return instance; - } - private SunLayoutEngine() { - // actually a factory, key is null so layout cannot be called on it - } - - public LayoutEngine getEngine(Font2D font, int script, int lang) { - return getEngine(new LayoutEngineKey(font, script, lang)); - } - - // !!! don't need this unless we have more than one sun layout engine... - public LayoutEngine getEngine(LayoutEngineKey key) { - ConcurrentHashMap cache = cacheref.get(); - if (cache == null) { - cache = new ConcurrentHashMap<>(); - cacheref = new SoftReference<>(cache); - } - - LayoutEngine e = cache.get(key); - if (e == null) { - LayoutEngineKey copy = key.copy(); - e = new SunLayoutEngine(copy); - cache.put(copy, e); - } - return e; - } - private SoftReference> cacheref = - new SoftReference<>(null); - - private SunLayoutEngine(LayoutEngineKey key) { - this.key = key; } private static final WeakHashMap facePtr = new WeakHashMap<>(); - private long getFacePtr(Font2D font2D) { + private static long getFacePtr(Font2D font2D) { FaceRef ref; synchronized (facePtr) { ref = facePtr.computeIfAbsent(font2D, FaceRef::new); @@ -170,17 +67,16 @@ public final class SunLayoutEngine implements LayoutEngine, LayoutEngineFactory } - public void layout(FontStrikeDesc desc, float[] mat, float ptSize, int gmask, + public static void layout(Font2D font, int script, FontStrikeDesc desc, float[] mat, float ptSize, int gmask, int baseIndex, TextRecord tr, int typo_flags, Point2D.Float pt, GVData data) { - Font2D font = key.font(); FontStrike strike = font.getStrike(desc); if (useFFM) { MemorySegment face = HBShaper.getFace(font); if (face != null) { HBShaper.shape(font, strike, ptSize, mat, face, - tr.text, data, key.script(), + tr.text, data, script, tr.start, tr.limit, baseIndex, pt, typo_flags, gmask); } @@ -188,7 +84,7 @@ public final class SunLayoutEngine implements LayoutEngine, LayoutEngineFactory long pFace = getFacePtr(font); if (pFace != 0) { shape(font, strike, ptSize, mat, pFace, - tr.text, data, key.script(), + tr.text, data, script, tr.start, tr.limit, baseIndex, pt, typo_flags, gmask); }